function Day(dayDto, parentMonth) {
    this._date = (dayDto.date.constructor === String ? Date.parse(dayDto.date) : dayDto.date);
    this._location = dayDto.location || null;
    this._activity = dayDto.activity || DayActivity.empty;
    this._secondActivity = dayDto.secondActivity || DayActivity.empty;
    this._travelSteps = [];
    this._parentMonth = parentMonth;
    this._note = null;    
}

Day.prototype = {
    isCompleted: function() {
        return this._hasAtLeastOneActivity() && this._hasLocationOrOnTravel();
    },

    _hasAtLeastOneActivity: function() {
        return this._activity != DayActivity.empty;
    },

    _hasLocationOrOnTravel: function() {
        return this.hasTravel() || this._location != null;
    },

    isMissingTravel: function(previousDay) {
        if (this._hasInnerMissingTravel()) {
            return true;
        }
        if (previousDay === undefined || previousDay === null) {
            return false;
        }

        if (this.hasTravel() && previousDay.hasTravel()) {
            if (this._hasSameTravelWithPreviousDay(previousDay)) {
                return false;
            }
        }
        var myLocation = this.hasTravel() ? this._getFirstTravelStep().getDepartureLocation() : this.getLocation();
        var previousLocation = previousDay.hasTravel() ? previousDay._getLastTravelStep().getArrivalLocation() : previousDay.getLocation();
        return this._hasMissingTravelBetween(previousLocation, myLocation);
    },

    _getFirstTravelStep: function() {
        return this._travelSteps[0];
    },

    _getLastTravelStep: function() {
        return this._travelSteps[this._travelSteps.length - 1];
    },
    _hasSameTravelWithPreviousDay: function(previousDay) {
        return this._getFirstTravelStep().equals(previousDay._getLastTravelStep());
    },
    _hasInnerMissingTravel: function() {
        var me = this;
        var travelSteps = this.getTravelSteps();
        var firstMissingTravel = travelSteps.findFirst(function(currentStep, index) {
            return index == 0 ? false
                              : me._hasMissingTravelBetween(travelSteps[index - 1].getArrivalLocation(), currentStep.getDepartureLocation());
        });
        return !!firstMissingTravel;
    },

    _hasMissingTravelBetween: function(location1, location2) {
        return location1 !== null && location2 !== null && !location1.equals(location2);
    },

    clone: function() {
        var newDay = new Day(this.toDto(), this._parentMonth);
        this._travelSteps.foreach(function(travelStep) {
            newDay.addTravelStep(travelStep);
        });
        return newDay;
    },

    addTravelStep: function(travelStep) {
        this._travelSteps.push(travelStep);
    },

    getTravelSteps: function() {
        return this._travelSteps;
    },

    getDepartureDateTimes: function() {
        var me = this;
        return this._travelSteps.where(function(travelStep) {
            return me.getDate().sameDay(travelStep.getDepartureDate());
        }).select(function(travelStep) {
            return travelStep.getDepartureDateTime();
        });
    },

    isBlank: function() {
        return this._activity === DayActivity.empty && this._location === null && !this.hasTravel();
    },

    getDate: function() {
        return this._date.clone();
    },

    getLocation: function() {
        return this._location;
    },

    setLocation: function(location) {
        this._location = location;
    },

    hasActivity: function(activity) {
        return this._activity == activity || this._secondActivity == activity;
    },

    getActivity: function() {
        return this._activity;
    },
    setActivity: function(activity) {
        this._activity = activity;
    },

    getSecondActivity: function() {
        return this._secondActivity;
    },

    setSecondActivity: function(activity) {
        this._secondActivity = activity;
    },
    getActivities: function() {
        var activities = [];
        if (this._activity != DayActivity.empty) {
            activities.push(this._activity);
        }
        if (this._secondActivity != DayActivity.empty) {
            activities.push(this._secondActivity);
        }
        return activities;
    },

    getLocationsOnTravels: function() {
        var locations = [];
        this._travelSteps.foreach(function(step) {
            locations.uniquePush(step.getDepartureLocation());
            locations.uniquePush(step.getArrivalLocation());
        });
        return locations;
    },
    getStatus:function(){
        if(this._date > new Date()){
            return CompleteStatus.future;
        }
       return this.isCompleted()? CompleteStatus.complete: CompleteStatus.incomplete;  
    },
    
    parentMonth: function() {
        return this._parentMonth;
    },

    isInMonth: function(yearMonth) {
        return yearMonth.isSameWith(this._date.toYearMonth());
    },
    toDto: function() {
        return { "date": this._date.toString("yyyy-MM-dd"), "activity": this._activity, "secondActivity": this._secondActivity, "location": this._location };
    },

    isDuringTravel: function() {
        if (this._travelSteps.length !== 1) {
            return false;
        }
        var travelStep = this._travelSteps[0];
        var departureDate = travelStep.getDepartureDate();
        var arrivalDate = travelStep.getArrivalDate();
        var currentDate = this.getDate();
        return currentDate > departureDate && currentDate < arrivalDate;
    },
    hasTravel: function() {
        return this._travelSteps.length > 0;
    },

    setNote: function(note) {
        this._note = note;
    },
    hasNote: function() {
        return !!this._note;
    },
    getNote:function(){
        return this._note;
    },
    clearLocationAndActivity: function() {
        this.setLocation(null);
        this.setActivity('');
    },

    getLocations: function(){
        return this.getLocationInfos().select(function(info) { return info.location; }).unique();
    },

    getLocationInfos: function() {
        var locationInfos = [];
        var date = this.getDate();

        if (!this.hasTravel()) {
            locationInfos.push(new DayLocationInfo(this.getLocation(), date, null));
            return locationInfos;
        }

        if (this.isDuringTravel()) {
            locationInfos.push(new DayLocationInfo(this._travelSteps[0].getArrivalLocation(), date, null));
            return locationInfos;
        }

        return this._collectLocationInfosInTravelSteps();
    },

    _collectLocationInfosInTravelSteps: function() {
        var me = this;
        var locationInfos = [];
        var date = me.getDate();
        me._travelSteps.foreach(function(travelStep, i) {
            if (me._isDepartureDay(travelStep)) {
                locationInfos.push(new DayLocationInfo(travelStep.getDepartureLocation(), date, travelStep.getDepartureDateTime()));
            }
            if (i == me._travelSteps.length - 1 || me._isArrivalDay(travelStep)) {
                locationInfos.push(new DayLocationInfo(travelStep.getArrivalLocation(), date, null));
            }
        });
        return locationInfos;
    },

    _isArrivalDay: function(travelStep) {
        return this.getDate().sameDay(travelStep.getArrivalDate());        
    },

    _isDepartureDay: function(travelStep) {
        return this.getDate().sameDay(travelStep.getDepartureDate());        
    }
};

function DayLocationInfo(location, date, departureTime){
    this.location = location;
    this.date = date;
    this.departureTime = departureTime;
}

DayLocationInfo.prototype = {
    getDayStartTime: function(){
        return this.date.clone().clearTime();
    },
    getLocationEndTime: function(){
        return this.departureTime || this.date.clone().clearTime().addDays(1).addSeconds(-1);
    },
    hasLocation: function(){
        return this.location != null;
    }
};

function DayEvent(location, activity) {
    this.location = location || null;
    this.activity = activity || DayActivity.empty;
}

DayEvent.prototype = {
    equals : function(other) {
        return this.activity === other.activity && this.location.equals(other.location);
    },

    isBlank : function() {
        return this.activity === DayActivity.empty && this.location === null;
    },

    isCompleted : function(){
        return this.activity !== DayActivity.empty && Location.isValidLocation(this.location);
    }
};


var DayActivity = { empty: '', work: 'work', sick: 'sick', vacation: 'vacation', national: 'national', other: 'other' };
var DayActivityLabelMapping = { work: i18n("LABEL_ACTIVITY_WORK_TIP"), sick: i18n("LABEL_ACTIVITY_SICK_TIP"), vacation: i18n("LABEL_ACTIVITY_PAID_TIME_OFF_TIP"), national: i18n("LABEL_ACTIVITY_NATIONAL_HOLIDAY_TIP"), other: i18n("LABEL_ACTIVITY_OTHER_TIP") };


